package core;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * JSON序列化工具（空值安全优化版）
 * <p>
 * 参考Hutool的JSONUtil实现，提供完整的JSON处理功能。
 * </p>
 */
public final class JsonUtil {
    private static final ObjectMapper MAPPER = new ObjectMapper();

    private JsonUtil() {
        throw new AssertionError("Utility class");
    }

    // -------------------------------------------------------------------- Create start

    /**
     * 创建ObjectNode（类似JSONObject）
     *
     * @return ObjectNode
     */
    public static ObjectNode createObject() {
        return MAPPER.createObjectNode();
    }

    /**
     * 创建ArrayNode（类似JSONArray）
     *
     * @return ArrayNode
     */
    public static ArrayNode createArray() {
        return MAPPER.createArrayNode();
    }

    // -------------------------------------------------------------------- Create end

    // -------------------------------------------------------------------- Parse start

    /**
     * JSON字符串转ObjectNode对象
     *
     * @param jsonStr JSON字符串
     * @return ObjectNode
     */
    public static ObjectNode parseObject(String jsonStr) {
        if (ObjectUtil.isEmpty(jsonStr)) {
            return createObject();
        }
        try {
            return (ObjectNode) MAPPER.readTree(jsonStr);
        } catch (JsonProcessingException e) {
            throw new JsonProcessingRuntimeException("Parse JSON object error", e);
        }
    }

    /**
     * JSON字符串转ArrayNode对象
     *
     * @param jsonStr JSON字符串
     * @return ArrayNode
     */
    public static ArrayNode parseArray(String jsonStr) {
        if (ObjectUtil.isEmpty(jsonStr)) {
            return createArray();
        }
        try {
            return (ArrayNode) MAPPER.readTree(jsonStr);
        } catch (JsonProcessingException e) {
            throw new JsonProcessingRuntimeException("Parse JSON array error", e);
        }
    }

    // -------------------------------------------------------------------- Parse end

    /**
     * 对象序列化（空值安全）
     *
     * @param obj 待序列化对象
     * @return JSON字符串（输入空时返回空字符串）
     */
    public static String toJson(Object obj) {
        if (ObjectUtil.isEmpty(obj)) {
            return "";
        }
        try {
            return MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new JsonProcessingRuntimeException("Serialization error", e);
        }
    }

    /**
     * 对象序列化为格式化的JSON字符串
     *
     * @param obj 待序列化对象
     * @return 格式化的JSON字符串
     */
    public static String toJsonPretty(Object obj) {
        if (ObjectUtil.isEmpty(obj)) {
            return "";
        }
        try {
            return MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            throw new JsonProcessingRuntimeException("Pretty serialization error", e);
        }
    }

    /**
     * 基础对象反序列化
     *
     * @param json  JSON字符串
     * @param clazz 目标类型
     * @return 反序列化后的对象（输入空时返回null）
     */
    public static <T> T fromJson(String json, Class<T> clazz) {
        if (ObjectUtil.isEmpty(json)) {
            return null;
        }
        try {
            return MAPPER.readValue(json, clazz);
        } catch (JsonProcessingException e) {
            throw new JsonProcessingRuntimeException(
                    "Deserialization error for type: " + clazz.getName(), e);
        }
    }

    /**
     * List序列化（空值安全）
     *
     * @param list 待序列化List
     * @return JSON字符串（输入空时返回空数组字符串）
     */
    public static <T> String listToJson(List<T> list) {
        if (ObjectUtil.isEmpty(list)) return "[]";
        try {
            return MAPPER.writeValueAsString(list);
        } catch (JsonProcessingException e) {
            throw new JsonProcessingRuntimeException("List serialization error", e);
        }
    }

    /**
     * 反序列化为List集合
     *
     * @param json        JSON字符串
     * @param elementType List元素类型
     * @return List集合（输入空时返回空列表）
     */
    public static <T> List<T> listFromJson(String json, Class<T> elementType) {
        if (ObjectUtil.isEmpty(json)) return Collections.emptyList();
        try {
            return MAPPER.readValue(json,
                    MAPPER.getTypeFactory().constructCollectionType(List.class, elementType));
        } catch (JsonProcessingException e) {
            throw new JsonProcessingRuntimeException(
                    "List deserialization error for element type: " + elementType.getName(), e);
        }
    }

    /**
     * Map序列化（空值安全）
     *
     * @param map 待序列化Map
     * @return JSON字符串（输入空时返回空对象字符串）
     */
    public static <K, V> String mapToJson(Map<K, V> map) {
        if (ObjectUtil.isEmpty(map)) return "{}";
        try {
            return MAPPER.writeValueAsString(map);
        } catch (JsonProcessingException e) {
            throw new JsonProcessingRuntimeException("Map serialization error", e);
        }
    }

    /**
     * Map反序列化
     *
     * @param json      JSON字符串
     * @param keyType   Map键类型
     * @param valueType Map值类型
     * @return Map对象（输入空时返回空Map）
     */
    public static <K, V> Map<K, V> mapFromJson(String json, Class<K> keyType, Class<V> valueType) {
        if (ObjectUtil.isEmpty(json)) return Collections.emptyMap();
        try {
            return MAPPER.readValue(json,
                    MAPPER.getTypeFactory().constructMapType(Map.class, keyType, valueType));
        } catch (JsonProcessingException e) {
            throw new JsonProcessingRuntimeException(
                    "Map deserialization error for types: " + keyType.getName() + "/" + valueType.getName(),
                    e);
        }
    }

    /**
     * 通用泛型反序列化方法（适用于复杂嵌套类型）
     *
     * @param json          JSON字符串
     * @param typeReference 类型引用
     * @return 反序列化后的对象（输入空时返回null）
     */
    public static <T> T fromJson(String json, TypeReference<T> typeReference) {
        if (ObjectUtil.isEmpty(json)) return null;
        try {
            return MAPPER.readValue(json, typeReference);
        } catch (JsonProcessingException e) {
            throw new JsonProcessingRuntimeException(
                    "Deserialization error for complex type: " + typeReference.getType().getTypeName(),
                    e);
        }
    }

    // -------------------------------------------------------------------- Bean conversion start

    /**
     * JSON字符串转为实体类对象
     *
     * @param <T>        Bean类型
     * @param jsonString JSON字符串
     * @param beanClass  实体类对象
     * @return 实体类对象
     */
    public static <T> T toBean(String jsonString, Class<T> beanClass) {
        return fromJson(jsonString, beanClass);
    }

    /**
     * 将ArrayNode转换为Bean的List
     *
     * @param <T>         Bean类型
     * @param arrayNode   ArrayNode
     * @param elementType List中元素类型
     * @return List
     */
    public static <T> List<T> toList(ArrayNode arrayNode, Class<T> elementType) {
        if (arrayNode == null) return Collections.emptyList();
        try {
            return MAPPER.convertValue(arrayNode,
                    MAPPER.getTypeFactory().constructCollectionType(List.class, elementType));
        } catch (IllegalArgumentException e) {
            throw new JsonProcessingRuntimeException(
                    "List conversion error for element type: " + elementType.getName(), e);
        }
    }

    // -------------------------------------------------------------------- Bean conversion end

    // -------------------------------------------------------------------- JSON check start

    /**
     * 是否为JSON类型字符串，首尾都为大括号或中括号判定为JSON字符串
     *
     * @param str 字符串
     * @return 是否为JSON类型字符串
     */
    public static boolean isJson(String str) {
        return isJsonObject(str) || isJsonArray(str);
    }

    /**
     * 是否为JSONObject类型字符串，首尾都为大括号判定为JSONObject字符串
     *
     * @param str 字符串
     * @return 是否为JSONObject类型字符串
     */
    public static boolean isJsonObject(String str) {
        if (ObjectUtil.isEmpty(str)) {
            return false;
        }
        str = str.trim();
        return str.startsWith("{") && str.endsWith("}");
    }

    /**
     * 是否为JSONArray类型字符串，首尾都为中括号判定为JSONArray字符串
     *
     * @param str 字符串
     * @return 是否为JSONArray类型字符串
     */
    public static boolean isJsonArray(String str) {
        if (ObjectUtil.isEmpty(str)) {
            return false;
        }
        str = str.trim();
        return str.startsWith("[") && str.endsWith("]");
    }

    // -------------------------------------------------------------------- JSON check end

    // -------------------------------------------------------------------- File read start

    /**
     * 读取JSON文件
     *
     * @param file    JSON文件
     * @param charset 编码
     * @return JSON字符串
     */
    public static String readJson(File file, Charset charset) {
        if (file == null || !file.exists()) {
            return "";
        }
        try {
            return StringUtil.utf8Str(java.nio.file.Files.readAllBytes(file.toPath()));
        } catch (IOException e) {
            throw new JsonProcessingRuntimeException("Read JSON file error", e);
        }
    }

    /**
     * 读取JSON文件
     *
     * @param filePath 文件路径
     * @return JSON字符串
     */
    public static String readJson(String filePath) {
        return readJson(new File(filePath), StandardCharsets.UTF_8);
    }

    // -------------------------------------------------------------------- File read end

    /**
     * 获取可配置的ObjectMapper实例
     */
    public static ObjectMapper configurableMapper() {
        return MAPPER.copy();
    }

    /**
     * 自定义JSON处理运行时异常
     */
    public static class JsonProcessingRuntimeException extends RuntimeException {
        public JsonProcessingRuntimeException(String message) {
            super(message);
        }

        public JsonProcessingRuntimeException(String message, Throwable cause) {
            super(message, cause);
        }
    }
}